/*****************************************************************************
*
*  PROJECT:     SlipStream
*               (KeyBinds Manager)
*  LICENSE:     GNU General Public License v3 - http://www.gnu.org/licenses/gpl.html

*  DEVELOPERS:  Philip Farquharson	<B00137077@studentmail.uws.ac.uk>
*				John Gray			<B00145524@studentmail.uws.ac.uk>		
*				Zohaib Bhatti		<B00104280@studentmail.uws.ac.uk>
*				Euan Hislop			<B00138636@studentmail.uws.ac.uk>
*
*****************************************************************************/
#include "CKeyBindManager.h"

template<> CKeyBindManager * CSingleton< CKeyBindManager >::m_pSingleton = NULL;

CKeyBindManager::CKeyBindManager ( void ) { m_bHasFocus = false; } // set our focus state to false on creation
CKeyBindManager::~CKeyBindManager ( void )
{
	
	std::list<CKeyBind*>::const_iterator iter = m_binds.begin (); // create an iterator of our binds list
	for ( ; iter != m_binds.end(); ++iter ) // iterate the binds
	{
		CKeyBind* pKeyBind = static_cast < CKeyBind* > ( *iter ); // get the current object in the iterator and statically cast it over to a CKeyBind pointer

		assert ( pKeyBind ); // assert pKeyBind != NULL

		// free our resources
		SAFE_DELETE( pKeyBind );
	}
}

// Binds a key, takes a void callback function, a key and bind type.
CKeyBind* CKeyBindManager::bindKey ( KeybindCallback CallBack, CKeyBind::eKey key, CKeyBind::eBindType bindType )
{
	// check we don't have a bind existing with the same parameters
	std::list<CKeyBind*>::const_iterator iter = m_binds.begin(); // create an iterator of our binds list
	for ( ; iter != m_binds.end (); ++iter ) // iterate the binds
	{
		CKeyBind* pKeyBind = static_cast < CKeyBind* > ( *iter ); // get the current object in the iterator and statically cast it over to a CKeyBind pointer

		assert ( pKeyBind ); // assert pKeyBind != NULL

		if ( pKeyBind->getCallback () == CallBack && pKeyBind->getKey () == key && pKeyBind->getType () == bindType ) // if the parameters of the iterator keybind match the ones of the keybind we wish to add
			return pKeyBind; // return the iterator keybind as it is the one we wanted to create
	}

	// if the keybind doesn't exist currently
	CKeyBind* pKeyBind = new CKeyBind ( CallBack, key, bindType ); // create a new keybind with the parameters
	m_binds.push_back ( pKeyBind ); // push the new keybind onto the list
	return pKeyBind; // return the new keybind
}

void CKeyBindManager::Proc ( void )
{
	if ( m_bHasFocus ) // if we have focus
	{
		// iterate every bind and check if we should call the callback function
		std::list<CKeyBind*>::const_iterator iter = m_binds.begin(); // create an iterator of our binds list

		for ( ; iter != m_binds.end (); ++iter ) // iterate the binds
		{
			CKeyBind* pKeyBind = static_cast < CKeyBind* > ( *iter ); // get the current object in the iterator and statically cast it over to a CKeyBind pointer

			assert ( pKeyBind ); // assert pKeyBind != NULL

			if ( ( pKeyBind->getType() == CKeyBind::BIND_SIMPLE || ( pKeyBind->getType() == CKeyBind::BIND_TOGGLE && clock() - pKeyBind->getMS() > 200 ) ) && GetAsyncKeyState ( pKeyBind->getKey() )) // if the key is being pressed, and its either not a toggle bind or the toggle bind has no cooldown period on it
			{
				pKeyBind->Proc (); // call the callback function
			}
		}
	}
}

bool CKeyBindManager::removeBind ( CKeyBind* pKeyBind )
{
	int cBinds = m_binds.size (); // store the number of binds we have before removal
	m_binds.remove ( pKeyBind ); // try to remove the pKeyBind if it exists

	return ( cBinds != m_binds.size () ); // return true if the size has changed, false otherwise as we haven't removed anything
}

bool CKeyBindManager::removeBind ( KeybindCallback CallBack, CKeyBind::eKey key, int type )
{
	// iterate every bind until we find the matching one and pop it off the list

	std::list<CKeyBind*>::const_iterator iter = m_binds.begin(); // create an iterator of our binds list
	bool removed = false; // flag if we removed anything or not

	for ( ; iter != m_binds.end (); ++iter ) // iterate the binds
	{
		CKeyBind* pKeyBind = static_cast < CKeyBind* > ( *iter ); // get the current object in the iterator and statically cast it over to a CKeyBind pointer

		assert ( pKeyBind ); // assert pKeyBind != NULL

		if ( pKeyBind->getCallback() == CallBack && pKeyBind->getKey() == key && pKeyBind->getType() == type ) // match found
		{
			m_binds.remove( pKeyBind ); // pop it off the list
			SAFE_DELETE ( pKeyBind ); // delete it
			removed = true; // set the removed flag to true
			break; // break the loop to save some cpu cycles, as we can't have more than one matching bind anyway
		}
	}

	return removed;
}